# -*- coding: utf-8 -*-
#!/usr/bin/env python
import datetime
import logging
import os

import tornado.escape
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

from tornado.options import define, options

from model import (
    User, UserDetail, Dish,
    Recipe, Headline, session)

from session import WebSession
import uimodules
from utils import random_string, random_digits

define("port", default=8888, help="run on the given port", type=int)


class BaseHandler(tornado.web.RequestHandler):
    '''Base Request Handler with auth and seesion'''
    def get_current_user(self):
        return self.session()["user"]

    def session(self):
        if hasattr(self, '_session'):
            return self._session
        session_id = self.get_secure_cookie('SESSID')
        if session_id:
            logging.debug('SESSID: %s' % session_id)
            self._session = WebSession(session_id)
        else:
            self._session = WebSession()
            self.set_secure_cookie('SESSID', self._session.id)
        return self._session


class LoginHandler(BaseHandler):
    def get(self):
        next = self.get_argument("next", '/')
        errno = self.get_argument("errno", 0)
        self.render('login.html', next=next, errno=str(errno))

    def post(self):
        uid = self.get_argument("uid", '')
        upw = self.get_argument("upw", '')
        next = self.get_argument("next", '/')
        if User.valid(uid, upw):
            u = session.query(User).filter(User.nickname == uid).first()
            self.session()['user'] = {'nickname': uid, 'uid': u.id}
            self.redirect(next)
        else:
            errno = 2
            self.redirect("/auth/login?errno=%d" % errno)


class RegisterHandler(BaseHandler):
    def get(self):
        next = self.get_argument("next", '/')
        info = self.get_argument("info", '')
        self.render('register.html', next=next, info=info)

    def post(self):
        uid = self.get_argument("uid", '')
        upw = self.get_argument("upw", '')
        next = self.get_argument("next", '/')
        nickname = self.get_argument("nickname", '/')
        result, info = User.register(uid, upw, nickname)

        if result:
            u = session.query(User).filter(User.nickname == uid).first()
            self.session()['user'] = {'nickname': uid, 'uid': u.id}
            self.redirect(next)
        else:
            self.redirect("/auth/register?next=%s&info=%s" % (next, info))


class LogoutHandler(BaseHandler):
    def get(self):
        self.clear_cookie("SESSID")
        self.redirect("/")


class MainHandler(BaseHandler):
    def get(self):
        # headline recipe list
        headline = Headline.get_headline(10)
        # trend recipe list
        trend = Recipe.get_trend(10)
        # recent recipe list
        recent = Recipe.get_recent(10)
        #  category list
        category = []
        # search word list
        search_words = []
        self.render(
            'index.html', headline=headline, trend=trend,
            recent=recent, category=category, search_words=search_words)


class RecipeHandler(BaseHandler):
    def get(self, id):
        recipe = session.query(Recipe).filter(Recipe.id == id).first()
        if recipe:
            user = session.query(User)\
                .filter(User.id == recipe.user_id).first()
            dishes = session.query(Dish)\
                .filter(Dish.recipe_id == recipe.id).all()
            self.render('recipe.html', recipe=recipe, dishes=dishes, user=user)
        else:
            raise tornado.web.HTTPError(404)


class RecipeCreateHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self):
        hash_id = random_string(10)
        self.render('recipe_create.html', hash_id=hash_id)

    @tornado.web.authenticated
    def post(self):
        # handle arguments
        user_id = self.get_current_user().get('uid')
        arguments = ['title', 'intro', 'tips']
        kw = {}
        for a in arguments:
            kw[a] = self.get_argument(a, '')
        kw['ctime'] = datetime.datetime.now()
        kw['dish_counter'] = 0
        steps_pic = []
        for info in self.get_arguments('temp_img'):
            pic_id, usage = info.split('-')
            if usage == 'cover':
                kw['pic_url'] = '/temp_pic?pic_id=%s' % pic_id
            elif usage == 'steps':
                steps_pic.append(pic_id)
        steps_desc = self.get_arguments('step')
        detail = [
            (d, p) for d, p in zip(steps_desc, steps_pic)
            if d or (p != '0')]
        kw['detail'] = tornado.escape.json_encode(detail)
        ings = self.get_arguments('ing')
        units = self.get_arguments('unit')
        material = [(i, u) for i, u in zip(ings, units) if i or u]
        kw['material'] = tornado.escape.json_encode(material)
        recipe = Recipe(user_id=user_id, **kw)
        session.add(recipe)
        session.flush()
        self.redirect('/recipe/%s' % recipe.id)


class RecipeEditHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, id):
        recipe = session.query(Recipe).filter(Recipe.id == id).first()
        hash_id = random_string(10)
        self.render(
            'recipe_edit.html', recipe=recipe, hash_id=hash_id)

    @tornado.web.authenticated
    def post(self, id):
        # handle arguments
        user_id = self.get_current_user().get('uid')
        recipe = session.query(Recipe).filter(Recipe.id == id).first()
        if recipe.user_id != user_id:
            raise tornado.web.HTTPError(403)
        arguments = ['title', 'intro', 'tips']
        for a in arguments:
            setattr(recipe, a, self.get_argument(a, ''))
        steps_pic = []
        for info in self.get_arguments('temp_img'):
            pic_id, usage = info.split('-')
            if usage == 'cover':
                recipe.pic_url = '/temp_pic?pic_id=%s' % pic_id
            elif usage == 'steps':
                steps_pic.append(pic_id)
        steps_desc = self.get_arguments('step')
        detail = [
            (d, p) for d, p in zip(steps_desc, steps_pic)
            if d or (p != '0')]
        recipe.detail = tornado.escape.json_encode(detail)
        ings = self.get_arguments('ing')
        units = self.get_arguments('unit')
        material = [(i, u) for i, u in zip(ings, units) if i or u]
        recipe.material = tornado.escape.json_encode(material)
        session.flush()
        self.redirect('/recipe/%s' % recipe.id)


class RecipeDeleteHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, id):
        # handle arguments
        user_id = self.get_current_user().get('uid')
        recipe = session.query(Recipe).filter(Recipe.id == id).first()
        if recipe.user_id != user_id:
            raise tornado.web.HTTPError(403)
        session.delete(recipe)
        session.flush()
        self.redirect('/')


class DishHandler(BaseHandler):
    def get(self, id):
        dish = session.query(Dish).filter(Dish.id == id).first()
        if dish:
            recipe = session.query(Recipe)\
                .filter(Recipe.id == dish.recipe_id).first()
            user = session.query(User)\
                .filter(User.id == dish.user_id).first()
            self.render('dish.html', dish=dish, user=user, recipe=recipe)
        else:
            raise tornado.web.HTTPError(404)


class DishCreateHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, recipe_id):
        self.render('dish_create.html')

    @tornado.web.authenticated
    def post(self, recipe_id):
        # handle arguments
        user_id = self.get_current_user().get('uid')
        recipe_id = recipe_id
        arguments = ['intro']
        kw = {}
        for a in arguments:
            kw[a] = self.get_argument(a, '')
        kw['ctime'] = datetime.datetime.now()
        for info in self.get_arguments('temp_img'):
            pic_id, usage = info.split('-')
            if usage == 'cover':
                kw['pic_url'] = '/temp_pic?pic_id=%s' % pic_id
        dish = Dish(user_id=user_id, recipe_id=recipe_id, **kw)
        session.add(dish)
        session.flush()
        self.redirect('/dish/%s' % dish.id)


class DishEditHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, id):
        dish = session.query(Dish).filter(Dish.id == id).first()
        pic_id = dish.pic_url.split('=')[1]
        self.render('dish_edit.html', dish=dish, pic_id=pic_id)

    @tornado.web.authenticated
    def post(self, id):
        # handle arguments
        user_id = self.get_current_user().get('uid')
        dish = session.query(Dish).filter(Dish.id == id).first()
        if dish.user_id != user_id:
            raise tornado.web.HTTPError(430)
        arguments = ['intro']
        for a in arguments:
            setattr(dish, a, self.get_argument(a, ''))
        for info in self.get_arguments('temp_img'):
            pic_id, usage = info.split('-')
            if usage == 'cover':
                dish.pic_url = '/temp_pic?pic_id=%s' % pic_id
        session.flush()
        self.redirect('/dish/%s' % dish.id)


class DishDeleteHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, id):
        # handle arguments
        user_id = self.get_current_user().get('uid')
        dish = session.query(Dish).filter(Dish.id == id).first()
        if dish.user_id != user_id:
            raise tornado.web.HTTPError(403)
        session.delete(dish)
        session.flush()
        self.redirect('/')


class CookHandler(BaseHandler):
    def get(self, id):
        user = session.query(User).filter(User.id == id).first()
        userdetail = session.query(UserDetail)\
            .filter(UserDetail.id == id).first()
        recipes = Recipe.get_by_user(id, 10)
        self.render(
            'cook.html', user=user, userdetail=userdetail, recipes=recipes)


class PicFrameHandler(BaseHandler):
    def get(self):
        hash_id = self.get_argument('hash_id')
        ptype = self.get_argument('ptype')
        self.render('pic_frame.html', hash_id=hash_id, ptype=ptype)


class TempPicHandler(BaseHandler):
    def get(self):
        pic_id = self.get_argument('pic_id')
        f = open('/tmp/'+pic_id, "r")
        self.write(f.read())
        f.close()


class UploadTempHandler(BaseHandler):
    def post(self):
        hash_id = self.get_argument('hash_id')
        f = self.request.files.get(u'filefield')
        ptype = self.get_argument('ptype')
        if not f:
            self.write('ok')
        else:
            # write to static file
            body = f[0].get('body')
            pic_id = random_digits(10)
            f = open('/tmp/'+pic_id, 'wb')
            f.write(body)
            f.close()
            pic_info = '-'.join([ptype, pic_id, ])
            self.render(
                'upload_temp.html', ptype=ptype, hash_id=hash_id,
                pic_id=pic_id, pic_info=pic_info)


class AccountHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self):
        user_id = self.get_current_user().get('uid')
        user = session.query(User).filter(User.id==user_id).first()
        userdetail = session.query(UserDetail).filter(UserDetail.id==user_id).first()
        self.render('account_basic.html', user=user, userdetail=userdetail)

    @tornado.web.authenticated
    def post(self):
        user_id = self.get_current_user().get('uid')
        user = session.query(User).filter(User.id==user_id).first()
        user.nickname = self.get_argument('nickname')
        userdetail = session.query(UserDetail).filter(UserDetail.id==user_id).first()
        if not userdetail:
            userdetail = UserDetail(id=user_id,
                intro='', gender='',
                birthday='', hometown='',
                city='', job='', pic_url='')
            session.add(userdetail)
        arguments = ['intro', 'gender', 'birthday', 'hometown',
            'city', 'job']
        for a in arguments:
            setattr(userdetail, a, self.get_argument(a, ''))
        session.flush()
        self.redirect('/account/basic/')


class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/", MainHandler),
            (r"/cook/([0-9]+)", CookHandler),
            (r"/account/basic/", AccountHandler),
            (r"/recipe/create", RecipeCreateHandler),
            (r"/recipe/([0-9]+)/edit", RecipeEditHandler),
            (r"/recipe/([0-9]+)/delete", RecipeDeleteHandler),
            (r"/recipe/([0-9]+)", RecipeHandler),
            (r"/recipe/([0-9]+)/create_dish", DishCreateHandler),
            (r"/dish/([0-9]+)/edit", DishEditHandler),
            (r"/dish/([0-9]+)/delete", DishDeleteHandler),
            (r"/dish/([0-9]+)", DishHandler),
            (r"/pic_frame", PicFrameHandler),
            (r"/upload_temp_pic", UploadTempHandler),
            (r"/temp_pic", TempPicHandler),
            (r"/auth/register", RegisterHandler),
            (r"/auth/login", LoginHandler),
            (r"/auth/logout", LogoutHandler),
        ]
        settings = dict(
            template_path=os.path.join(os.path.dirname(__file__), "templates"),
            static_path=os.path.join(os.path.dirname(__file__), "static"),
            cookie_secret='xcf_modify_this_when_release',
            login_url='/auth/login',
            autoescape=None,
            ui_modules=uimodules,
        )
        tornado.web.Application.__init__(self, handlers, **settings)


def main():
    tornado.options.parse_command_line()
    application = Application()
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()
